<?php
namespace App\Services;

use App\Enum\CouponEnum;
use App\Models\DrivingTariff;
use App\Models\Region;
use App\Models\ServiceCity;
use App\Models\Tariff;

/**
 *
 * Class PassengerCostService
 * @package App\Services
 */
class PassengerCostService extends BaseService
{


    /**
     * 根据经纬度获取预计金额
     * @param $origin
     * @param $destination
     * @param $boarding_time
     */
    public function getPredictByLoLa($origin, $destination, $boarding_time)
    {

        $amap  = new PassengerAmapService();
        $route = $amap->getDriveRoute(['origin'=> $origin, 'destination'=> $destination]);

        $path              = $route['paths'][0];
        $total_distance    = $path['distance']; //总距离 m
        $total_distance_km = intval($total_distance /1000 * 100)/ 100; //总距离 km
        $total_time        = $path['duration']; //总耗时
        $total_time_int_m  = ceil($total_time/60) * 60; //总耗时 整分
        $city_code         = $path['steps'][0]['cities'][0]['citycode']; //取第一个位子城市code
        $city_name         = mb_substr($path['steps'][0]['cities'][0]['name'], 0, 2); //取第一个位子城市code
        $city              = Region::query()->where('name', 'like', "{$city_name}%")->where('level', 2)->select(['id'])->first(); //todo 公司表、开通城市表缓存城市code
        $service_city_info = ServiceCity::query()->select(['default_user_company_id'])->firstWhere('city_id', $city->id);
        if(!$service_city_info)
            return_bob('该城市尚未开通', 0, 200);

        $company_tariffs = Tariff::query()
            ->where('company_id', $service_city_info->default_user_company_id)
            ->where('type', '1')
            ->whereHas('service_type')
            ->where('open_time', '<=', date('Y-m-d H:i:s', time()))
            ->orderByDesc('open_time')
            ->get();//todo 获取全部公司下服务
        //var_dump($company_tariffs);exit();

        if(!$company_tariffs)
            return_bob('该城市尚未开通', 0, 200);

        $polyline = array_column($path['steps'], 'polyline');//路线经纬度

        $predict  = [
            'city_id'        => $city->id,
            'total_time'     => $total_time_int_m,
            'total_distance' => $total_distance_km,
            'polyline'       => $polyline,
            'service_type'   => [],
        ];

        foreach ($company_tariffs as $k=> $tariff) {

            if (isset($predict['service_type'][$tariff->service_type_id]))
                continue;

            $predict['service_type'][$tariff->service_type_id] = [
                'service_type_id'             => $tariff->service_type_id,
                'name'                        => $tariff->service_type->name,
                'img'                         => $tariff->service_type->img,
                'accountability_cancel_time'  => $tariff->other_settings['accountability_cancel_time'],
                'accountability_cancel_price' => $tariff->other_settings['accountability_cancel_price'],
                'cost'                        => $this->calculatePredict($boarding_time, $total_time_int_m, $total_distance_km, $tariff)
            ];

        }
        return $predict;
    }

    /**
     * 代驾预估费计算
     */
    public function driving_tarff($origin, $destination, $boarding_time)
    {
        $amap  = new PassengerAmapService();
        $route = $amap->getDriveRoute(['origin'=> $origin, 'destination'=> $destination]);

        $path              = $route['paths'][0];
        $total_distance    = $path['distance']; //总距离 m
        $total_distance_km = intval($total_distance /1000 * 100)/ 100; //总距离 km
        $total_time        = $path['duration']; //总耗时
        $total_time_int_m  = ceil($total_time/60); //总耗时 整分
        $city_name         = mb_substr($path['steps'][0]['cities'][0]['name'], 0, 2); //取第一个位子城市code

        $city              = Region::query()->where('name', 'like', "{$city_name}%")->where('level', 2)->select(['id'])->first();
        $service_city_info = ServiceCity::query()->select(['default_user_company_id'])->where('city_id',$city->id)->first();
        if(!$service_city_info)
            return_bob('该城市尚未开通', 0, 200);
        $company_tariffs = DrivingTariff::query()
            ->where('company_id', $service_city_info->default_user_company_id)
            ->where('type', '1')
            ->where('open_time', '<=', date('Y-m-d H:i:s', time()))
            ->orderByDesc('open_time')
            ->first();
        if(!$company_tariffs)return_bob('该城市尚未开通', 0, 200);
        $predict['city_id']  = $city->id;
        $predict['service_type']= [
            'service_type_id'             => $company_tariffs->service_type_id,
            'name'                        => $company_tariffs->service_type->name,
            'img'                         => $company_tariffs->service_type->img,
            'accountability_cancel_time'  => $company_tariffs->other_settings['accountability_cancel_time'],
            'accountability_cancel_price' => $company_tariffs->other_settings['accountability_cancel_price'],
            'total_distance_km'           => $total_distance_km,
            'total_time_int_m'            => $total_time_int_m,
            'cost'                        => self::for_driving_amoute($boarding_time,$total_time_int_m,$total_distance_km,$company_tariffs)
        ];
       return $predict;
    }
    /**
     * 代驾费用计算
     */
    private function for_driving_amoute($start_time,$minute,$total_distance_km, object $tariffs)
    {
        $starting_price                       = $this->get_starting_priceCostByTime($start_time, $tariffs->starting_price);
        $default_minute_cost  = $this->mileageCost($start_time, $tariffs->mileage);
        //定义返回数据
        $predict = [
            'is_prepayment'            => 0, //是否需要预支付
            'unpaid_cost'              => 0, //需支付费用
            'starting_price'           => 0, //起步价
            'coupon_cost'              => 0, //预计优惠金额
            'user_coupon_id'           => 0, //预计优惠使用用户优惠ID
            'basics_cost'              => 0, //基础费用
            'total_cost'               => 0, //总费用
            'total_mileage_cost'       => 0, //总里程费用
            'total_duration_cost'      => 0, //总时长费
            'total_long_distance_cost' => 0, //长途总费用
            'mileage'                  => [], //里程费详情
            'duration'                 => [], //时长费详情
            'long_distance'            => [], //长途费详情
        ];
        if($starting_price['km']>=$total_distance_km && $starting_price['min']>=$minute){
            $predict['mileage'] = (object)[];
            $predict['unpaid_cost'] = $starting_price['price'];
            $predict['is_prepayment'] = $tariffs->other_settings['anticipation'] <= $predict['unpaid_cost']? 1: 0;
        }else{
            $total_distance_km = bcsub($total_distance_km,$starting_price['km'],2);
            $predict['unpaid_cost'] = bcadd($starting_price['price'],bcmul($default_minute_cost['price'],$total_distance_km,2),2);
            $predict['mileage'] =$default_minute_cost;
            $predict['is_prepayment'] = $tariffs->other_settings['anticipation'] <= $predict['unpaid_cost']? 1: 0;
        }
        //优惠券
        $passenger_user_coupon_service = new PassengerUserCouponService();
        $coupon_list = $passenger_user_coupon_service->getListAllByOrder($tariffs->service_type_id, $predict['unpaid_cost'], $start_time);
        if($coupon_list) {
            foreach ($coupon_list as $coupon) {
                $cur_coupon_price = $coupon['coupon']['type'] == CouponEnum::TypeProportion?
                    $predict['unpaid_cost'] * (10 - $coupon['coupon']['coupon_value']) /10 //折扣
                    :$coupon['coupon']['coupon_value']; //现金

                $cur_coupon_price = intval($cur_coupon_price*100) /100;
                if($predict['coupon_cost'] == 0 || $predict['coupon_cost']< $cur_coupon_price) {
                    $predict['coupon_cost']    = $cur_coupon_price;
                    $predict['user_coupon_id'] = $coupon['id'];
                }
            }
            $predict['unpaid_cost'] -= $predict['coupon_cost'];
        }
        $predict['unpaid_cost'] = intval(($predict['unpaid_cost'])*100) /100;
        return $predict;
    }
    /**
     * 根据时间获取里程费用
     */
    private function mileageCost( int $time ,array $rules)
    {
        $mileageCost = array_shift($rules);

        foreach ($rules as $key => $rule) {
            $start_time = strtotime($rule['start_time']);
            $end_time = $rule['end_time'] == '00:00'?
                strtotime($rule['end_time']) + 86400 //接受时间是0点 加1天
                :strtotime($rule['end_time']);
            if($time >= $start_time && $time < $end_time) {
                $mileageCost = $rule;
                break;
            }
        }

        return $mileageCost;
    }

    /**
     * todo 优化精确到秒
     * @param $boarding_time 上车时间 时间戳
     * @param $total_time  总时长 s
     * @param $total_distance_km 总里程 km
     * @param $tariff 资费规则
     */
    protected function calculatePredict(int $boarding_time, int $total_time, float $total_distance_km, object $tariff)
    {
        //所有资费信息
        $default_minute_cost                  = []; //默认资费
        $default_minute_cost['mileage_cost']  = $tariff->mileage[0]['price'];
        $default_minute_cost['duration_cost'] = $tariff->duration['data'][0]['price'];
        $day_minute_arr                       = range(0, 1440 -1 );
        $default_minute_cost_arr              = array_fill_keys($day_minute_arr, $default_minute_cost);// 默认费用
        $special_mileage_cost_arr             = $this->getMinuteCost($tariff->mileage, 'mileage_cost'); //特殊时段里程费用
        $special_duration_cost_arr            = $this->getMinuteCost($tariff->duration['data'], 'duration_cost'); //特殊时段时长费用
        $special_distance_km_cost_arr         = $this->getLongDistanceKmCost($tariff->distance, $total_distance_km); //特殊长途公里费用
        $basics_cost  =0;
        $starting_price = '';
        if($tariff->rules == '0'){
            $basics_cost                          = $this->getBasicsCostByTime($boarding_time, $tariff->basics);
        }else{
            $starting_price =   $this->get_starting_priceCostByTime($boarding_time,$tariff->starting_price);
        }
        //相关时间
        $arrive_time     = $boarding_time + $total_time; //预计到达时间
        $boarding_Hi_arr = explode(':', date('H:i', $boarding_time));
        $arrive_Hi_arr   = explode(':', date('H:i', $arrive_time));
        $boarding_minute = $boarding_Hi_arr[0]*60 + $boarding_Hi_arr[1];
        $arrive_minute   = $arrive_Hi_arr[0]*60 + $arrive_Hi_arr[1];
        $total_minute    = $total_time/60; //总分钟数
        $mileage_minute  = $total_distance_km / $total_minute; //每分钟公里

        //定义返回数据
        $predict = [
            'is_prepayment'            => 0, //是否需要预支付
            'unpaid_cost'              => 0, //需支付费用
            'starting_price'           => 0, //起步价
            'coupon_cost'              => 0, //预计优惠金额
            'user_coupon_id'           => 0, //预计优惠使用用户优惠ID
            'basics_cost'              => 0, //基础费用
            'total_cost'               => 0, //总费用
            'total_mileage_cost'       => 0, //总里程费用
            'total_duration_cost'      => 0, //总时长费
            'total_long_distance_cost' => 0, //长途总费用
            'mileage'                  => [], //里程费详情
            'duration'                 => [], //时长费详情
            'long_distance'            => [], //长途费详情
        ];

        //计算里程、时长费
        for ($minute = $boarding_minute; $minute <= $arrive_minute; $minute++) {

            $mileage_minute_cost  = 0;
            $duration_minute_cost = 0;
            $mileage_key          = '普通时段';
            $duration_key         = '普通时段';

            //特殊时段里程费
            foreach ($special_mileage_cost_arr as $key => $mileage_minute_cost_arr) {
                if (isset($mileage_minute_cost_arr[$minute])) { //在特殊时段里程费

                    $mileage_minute_cost = $mileage_minute_cost_arr[$minute] * $mileage_minute;
                    $mileage_key         = $key;

                }
            }

            //特殊时段时长费
            foreach ($special_duration_cost_arr as $key => $duration_minute_cost_arr) {
                if (isset($duration_minute_cost_arr[$minute])) { //在特殊时段里程费

                    $duration_minute_cost = $duration_minute_cost_arr[$minute];
                    $duration_key         = $key;

                }
            }

            $mileage_minute_cost = $mileage_minute_cost === 0 ?
                $default_minute_cost_arr[$minute]['mileage_cost'] * $mileage_minute //普通时段里程费
                : $mileage_minute_cost;

            $duration_minute_cost = $duration_minute_cost === 0 ?
                $default_minute_cost_arr[$minute]['duration_cost'] //普通时段时长费
                : $duration_minute_cost;

            $predict['mileage'][$mileage_key]   = isset($predict['mileage'][$mileage_key]) ?
                $predict['mileage'][$mileage_key] + $mileage_minute_cost //追加时段费用
                : $mileage_minute_cost;

            $predict['duration'][$duration_key] = isset($predict['duration'][$duration_key]) ?
                $predict['duration'][$duration_key] + $duration_minute_cost //追加时段费用
                : $duration_minute_cost;

        }

        //计算长途费
        if($special_distance_km_cost_arr) {

            $long_distance_start_km = key($special_distance_km_cost_arr);
            for ($km = $long_distance_start_km; $km <= ceil($total_distance_km); $km++) {

                $long_distance_cost = 0;
                $long_distance_key  = 0;

                //长途费用
                foreach ($special_distance_km_cost_arr as $key => $distance_km_cost) {

                    //当前实际公里数
                    $real_km = $km > $total_distance_km ?
                        $total_distance_km - intval($total_distance_km)
                        : 0;

                    if ($km >= $key) { //在长途范围内

                        $long_distance_cost = $real_km ?
                            $long_distance_cost + $distance_km_cost * $real_km
                            : $long_distance_cost + $distance_km_cost;
                        $long_distance_key = $key -1;

                    }

                }

                $long_distance_key = '超过' . $long_distance_key . '公里';
                $predict['long_distance'][$long_distance_key] = isset($predict['long_distance'][$long_distance_key]) ?
                    $predict['long_distance'][$long_distance_key] + $long_distance_cost
                    : $long_distance_cost;

            }
        }

        //格式化里程费、计算总里程费
        foreach ($predict['mileage'] as $key => $mileage_cost) {

            $mileage_cost                   = intval($mileage_cost * 100) / 100;
            $predict['mileage'][$key]       = $mileage_cost;
            $predict['total_mileage_cost'] += $mileage_cost;

        }

        //格式化时长费、计算总时长费
        foreach ($predict['duration'] as $key => $duration_cost) {

            $duration_cost                   = intval($duration_cost * 100) / 100;
            $predict['duration'][$key]       = $duration_cost;
            $predict['total_duration_cost'] += $duration_cost;

        }

        //格式化长途费、计算总时长费
        foreach ($predict['long_distance'] as $key => $long_distance_cost) {

            $long_distance_cost                   = intval($long_distance_cost * 100) / 100;
            $predict['long_distance'][$key]       = $long_distance_cost;
            $predict['total_long_distance_cost'] += $long_distance_cost;

        }

        $predict['basics_cost']   = intval($basics_cost * 100) /100;
        $predict['total_cost']    = intval(($predict['total_mileage_cost'] + $predict['total_duration_cost'] + $predict['total_long_distance_cost']) * 100) /100;
        $predict['starting_price'] = $starting_price?$starting_price['price']:0; //起步价
        if($tariff->rules=='0'){
            $predict['unpaid_cost']   = $predict['total_cost'] > $predict['basics_cost']? $predict['total_cost']: $predict['basics_cost'];
        }else{
            if($starting_price['km']>=$total_distance_km && $starting_price['min']>=$minute) $predict['unpaid_cost'] = $starting_price['price'];
            $predict['unpaid_cost']  = round($predict['total_cost']+$starting_price['price'],2);
        }
        $predict['is_prepayment'] = $tariff->other_settings['anticipation'] <= $predict['unpaid_cost']? 1: 0;

        //优惠券
        $passenger_user_coupon_service = new PassengerUserCouponService();
        $coupon_list = $passenger_user_coupon_service->getListAllByOrder($tariff->service_type_id, $predict['unpaid_cost'], $boarding_time);

        if($coupon_list) {
            foreach ($coupon_list as $coupon) {
                $cur_coupon_price = $coupon['coupon']['type'] == CouponEnum::TypeProportion?
                    $predict['unpaid_cost'] * (10 - $coupon['coupon']['coupon_value']) /10 //折扣
                    :$coupon['coupon']['coupon_value']; //现金

                $cur_coupon_price = intval($cur_coupon_price*100) /100;
                if($predict['coupon_cost'] == 0 || $predict['coupon_cost']< $cur_coupon_price) {
                    $predict['coupon_cost']    = $cur_coupon_price;
                    $predict['user_coupon_id'] = $coupon['id'];
                }
            }
            $predict['unpaid_cost'] -= $predict['coupon_cost'];
        }
        $predict['unpaid_cost'] = (intval(($predict['unpaid_cost'])*100) /100) >0?(intval(($predict['unpaid_cost'])*100) /100):0;

        return $predict;

    }
    /**
     * 根据时间获取当前起步费用
     * @param int $time
     * @param array $rules
     */
    protected function get_starting_priceCostByTime(int $time, array $rules)
    {
        $starting_price = array_shift($rules);
        foreach ($rules as $key => $rule) {

            $start_time = strtotime($rule['start_time']);
            $end_time = $rule['end_time'] == '00:00'?
                strtotime($rule['end_time']) + 86400 //接受时间是0点 加1天
                :strtotime($rule['end_time']);

            if($time >= $start_time && $time < $end_time) {
                $starting_price = $rule;
                break;
            }
        }

        return $starting_price;
    }

    /**
     * 根据时间获取当前 基础费用
     * @param int $time
     * @param array $rules
     */
    public function getBasicsCostByTime(int $time, array $rules)
    {

        $basics_cost = array_shift($rules)['price'];

        foreach ($rules as $key => $rule) {

            $start_time = strtotime($rule['start_time']);
            $end_time = $rule['end_time'] == '00:00'?
                strtotime($rule['end_time']) + 86400 //接受时间是0点 加1天
                :strtotime($rule['end_time']);

            if($time >= $start_time && $time < $end_time) {
                $basics_cost = $rule['price'];
                break;
            }
        }

        return $basics_cost;
    }


    /**
     * 获取每公里资费
     * @param array $rules
     * @param float $cur_distance_km
     * @return array
     */
    protected function getLongDistanceKmCost( array $rules , float $cur_distance_km)
    {
        $cur_distance_km = ceil($cur_distance_km);
        $km_cost_arr = [];

        foreach ($rules as $k => $rule) {
            if($rule['start_dist'] >= $cur_distance_km)//当前里程小于最小长途费 直接返回空数组
                break;

            $km_cost_arr[$rule['start_dist']+1] = $rule['price'];

        }

        asort($km_cost_arr);

        return $km_cost_arr;
    }


    /**
     * 获取每分钟 费用
     * @param $rules
     * @return array
     */
    protected function getMinuteCost( array $rules )
    {
        $minute_cost_arr = [];

        foreach ($rules as $k=> $rule) {

            if($rule['start_time'] == '普通时段') //第一条为默认价格
                continue;

            $rule['end_time']           = $rule['end_time'] == '00:00'? '24:00': $rule['end_time'];
            $row_start_arr              = explode(':', $rule['start_time']); //22:00
            $row_end_arr                = explode(':', $rule['end_time']); //24:00]
            $row_start_minute           = $row_start_arr[0] * 60 + $row_start_arr[1];
            $row_end_minute             = $row_end_arr[0] * 60 + $row_end_arr[1];
            $row_end_minute            -= 1; //规则结束时间减1
            $row_minute_arr             = range( $row_start_minute, $row_end_minute );
            $cost_key                   = $rule['start_time'].'-'.$rule['end_time'];
            $minute_cost_arr[$cost_key] = array_fill_keys($row_minute_arr, $rule['price']);

        }

        return $minute_cost_arr;
    }


    /**
     * 秒转化为具体时间 天小时分
     * @param int $time 时间戳
     */
    protected function sToDhm( int $time)
    {

        $dhm = 0;
        $d = floor($time / (3600*24));
        $h = floor(($time % (3600*24)) / 3600);
        $m = floor((($time % (3600*24)) % 3600) / 60);
        if ( $d>'0') {
            $dhm =  $d.'天'.$h.'小时'.$m.'分';
        } else {
            if ( $h!='0') {
                $dhm =  $h.'小时'.$m.'分';
            } else {
                $dhm =  $m.'分';
            }
        }

        return $dhm;
    }


}
